home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mission 3
/
Mission 3.zip
/
Mission 3.iso
/
texte
/
7up_pd
/
memory.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-10-29
|
10KB
|
406 lines
/* Eigene Speicherverwaltung. Kein Mfree(). Läuft instabil oder Bug in 7UP */
/*****************************************************************************
*
* 7UP
* Modul: MEMORY.C
* from GNU C-Library
* Best-/Lastfit Extension (c) TheoSoft '92
*
*****************************************************************************/
#include <portab.h>
#include <stdio.h>
#include <string.h>
#include <tos.h>
/* malloc, free, realloc: dynamic memory allocation */
/* msize, coreleft: size of memory */
#define GET 0
#define SET 1
#define FFIT 0
#define BFIT 1
#define LFIT 2
struct mem_chunk
{
struct mem_chunk *next;
unsigned long size;
};
int GetSetAllocationStrategy(int mode, int newstrategy, unsigned long *blksize);
static char *_ffmalloc(unsigned long n);
static char *_bfmalloc(unsigned long n);
static char *_lfmalloc(unsigned long n);
static char *_ffrealloc(struct mem_chunk *r, unsigned long n);
static char *_blfrealloc(struct mem_chunk *r, unsigned long n);
/* linked list of free blocks */
static struct mem_chunk _mchunk_free_list = { NULL, 0L };
/* minimum chunk to ask OS for (originally 4096Bytes) */
static unsigned long DEFAULT_BLKSIZE=32*1024L;
static int memallocstrat = FFIT;
int GetSetAllocationStrategy(int mode, int newstrategy, unsigned long *blksize)
{
switch(mode)
{
case GET:
*blksize=DEFAULT_BLKSIZE;
return(memallocstrat);
case SET:
switch(newstrategy)
{
case FFIT:
case BFIT:
case LFIT:
if(*blksize>=4*1024L)
{
DEFAULT_BLKSIZE=*blksize;
return(memallocstrat=newstrategy);
}
}
}
return(memallocstrat);
}
static char *_ffmalloc(register unsigned long n) /* first fit allocation */
{
register struct mem_chunk *p, *q;
register unsigned long sz;
/* add a mem_chunk to required size and round up */
n = n + sizeof(struct mem_chunk);
n = (7L + n) & ~7L;
/* look for first block big enough in free list */
p = &_mchunk_free_list;
q = _mchunk_free_list.next;
while ((q != NULL) && (q->size < n))
{
p = q;
q = q->next;
}
/* if not enough memory, get more from the system */
if (q == NULL)
{
sz = (n > DEFAULT_BLKSIZE ? n : DEFAULT_BLKSIZE);
q = (struct mem_chunk * )Malloc(sz);
if(!q) /* can't alloc any more? */
return(NULL);
p->next = q;
q->size = sz;
q->next = NULL;
}
if (q->size > (n + sizeof(struct mem_chunk)))
{ /* split, leave part of free list */
q->size -= n;
q = (struct mem_chunk * )(((unsigned long) q) + q->size);
q->size = n;
}
else
{ /* just unlink it */
p->next = q->next;
}
/* hand back ptr to after chunk desc */
return((char * )++q);
}
static char *_bfmalloc(register unsigned long n) /* best fit allocation */
{
register struct mem_chunk *p, *q, *bf = NULL;
register unsigned long sz, bfsize = 0xFFFFFFFF;
/* add a mem_chunk to required size and round up */
n = n + sizeof(struct mem_chunk);
n = (7L + n) & ~7L;
/* look for first block big enough in free list */
p = &_mchunk_free_list;
q = _mchunk_free_list.next;
while ((q != NULL) && (q->size != (n + sizeof(struct mem_chunk))))
{
if(q->size > n)
{
if((q->size - n) < bfsize)
{
bf = q;
bfsize = q->size - n;
}
}
p = q;
q = q->next;
}
if(q != NULL) /* just unlink it */
{
/* exactly found, what we want */
p->next = q->next;
}
else
{
if(bf != NULL)
{
/* this is our nearest block */
q = bf;
}
else
{
/* no smaller block available, allocate new one from OS */
sz = (n > DEFAULT_BLKSIZE ? n : DEFAULT_BLKSIZE);
q = (struct mem_chunk * )Malloc(sz);
if(!q) /* can't alloc any more? */
return(NULL);
p->next = q;
q->size = sz;
q->next = NULL;
}
if (q->size > (n + sizeof(struct mem_chunk)))
{ /* split, leave part of free list */
q->size -= n;
q = (struct mem_chunk * )(((unsigned long) q) + q->size);
q->size = n;
}
else
{ /* just unlink it */
p->next = q->next;
}
}
/* hand back ptr to after chunk desc */
return((char * )++q);
}
static char *_lfmalloc(register unsigned long n) /* last fit alloaction */
{
register struct mem_chunk *p, *q, *lf = NULL;
register unsigned long sz;
/* add a mem_chunk to required size and round up */
n = n + sizeof(struct mem_chunk);
n = (7L + n) & ~7L;
/* look for last block big enough in free list */
p = &_mchunk_free_list;
q = _mchunk_free_list.next;
while (q != NULL)
{
if(q->size > n)
lf = p;
p = q;
q = q->next;
}
if (lf != NULL)
{
/* this is our last block */
p = lf;
q = lf->next;
}
else
{
/* no smaller block available, allocate new one from OS */
sz = (n > DEFAULT_BLKSIZE ? n : DEFAULT_BLKSIZE);
q = (struct mem_chunk * )Malloc(sz);
if(!q) /* can't alloc any more? */
return(NULL);
p->next = q;
q->size = sz;
q->next = NULL;
}
if (q->size > (n + sizeof(struct mem_chunk)))
{ /* split, leave part of free list */
q->size -= n;
q = (struct mem_chunk * )(((unsigned long) q) + q->size);
q->size = n;
}
else
{ /* just unlink it */
p->next = q->next;
}
/* hand back ptr to after chunk desc */
return((char * )++q);
}
char *malloc(register unsigned long n)
{
if(n==0L) /* klar */
return(NULL);
switch(memallocstrat)
{
case FFIT:
return(_ffmalloc(n));
case BFIT:
return(_bfmalloc(n));
case LFIT:
return(_lfmalloc(n));
}
}
void free(register struct mem_chunk *r)
{
register struct mem_chunk *p, *q, *t;
if(r == NULL)
return;
/* move back to uncover the mem_chunk */
r--; /* there it is! */
/* stick it into free list, preserving ascending address order */
p = &_mchunk_free_list;
q = _mchunk_free_list.next;
while (q != NULL && q < r)
{
p = q;
q = q->next;
}
/* merge after if possible */
t = (struct mem_chunk * )(((unsigned long) r) + r->size);
if (q != NULL && t >= q)
{
r->size += q->size;
q = q->next;
}
r->next = q;
/* merge before if possible, otherwise link it in */
t = (struct mem_chunk * )(((unsigned long) p) + p->size);
if (t >= r)
{
p->size += r->size;
p->next = r->next;
}
else
p->next = r;
}
static char *_ffrealloc(struct mem_chunk *r, register unsigned long n) /* first fit */
{
register struct mem_chunk *p, *q;
unsigned long *src, *dst;
register unsigned long sz;
p = r - 1;
sz = (n + sizeof(struct mem_chunk) + 7L) & ~7L;
if (p->size > sz)
{ /* block too big, split in two */
q = (struct mem_chunk * )(((unsigned long) p) + sz);
q->size = p->size - sz;
free(q + 1);
p->size = sz;
}
else
{
if (p->size < sz)
{ /* block too small, get new one */
dst = q = (struct mem_chunk * )malloc(n);
if (q != NULL)
{
src = (unsigned long * )r;
n = p->size - sizeof(struct mem_chunk);
while (n > 0)
{
*dst++ = *src++;
n -= sizeof(unsigned long);
}
}
free(r);
r = q;
}
}
/* else current block will do just fine */
return((char * )r);
}
static char *_blfrealloc(struct mem_chunk *r, register unsigned long n) /* best fit */
{
register struct mem_chunk *p, *q;
unsigned long *src, *dst;
register unsigned long sz;
p = r - 1;
sz = (n + sizeof(struct mem_chunk) + 7L) & ~7L;
if (p->size != sz)
{
/* get new, best or last fit block */
dst = q = (struct mem_chunk * )malloc(n);
if (q != NULL)
{
src = (unsigned long * )r;
n = p->size - sizeof(struct mem_chunk);
memmove(dst, src, n);
}
free(r);
r = q;
}
/* else current block will do just fine */
return((char * )r);
}
char *realloc(struct mem_chunk *r, register unsigned long n)
{
switch(memallocstrat)
{
case FFIT:
return(_ffrealloc(r, n));
case BFIT:
case LFIT:
return(_blfrealloc(r, n));
}
}
char *calloc(register unsigned long n, register unsigned long sz)
{
register char *r;
if ((r = malloc(n * sz)) != NULL)
{
memset(r, 0, n * sz);
}
return(r);
}
unsigned long msize(register struct mem_chunk *r) /* size of allocated block */
{
return(r?(--r)->size - sizeof(struct mem_chunk):0L);
}
unsigned long coreleft(void) /* size of free mem */
{
register struct mem_chunk *p, *q;
register unsigned long freemem=0L;
p = &_mchunk_free_list;
q = _mchunk_free_list.next;
freemem+=p->size;
while (q != NULL)
{
freemem+=q->size;
p = q;
q = q->next;
}
return(freemem+(long)Malloc(-1L));
}